package com.hzya.frame.utils.help;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class DateHelper {
	public static final int FIRST_DAY_OF_WEEK = Calendar.MONDAY; // 中国周一是一周的第一天

	/**
	 * 设置时间格式
	 */
	private static final String COMMON_DATE = "yyyy-MM-dd";
	/**
	 * 设置东八区
	 **/
	private static final String UTC8 = "GMT+08:00";

	private DateHelper() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 锁对象
	 */
	private static final Object lockObj = new Object();

	/**
	 * 存放不同的日期模板格式的sdf的Map
	 */
	private static Map<String, ThreadLocal<SimpleDateFormat>> simpleDateFormatThreadLocalHashMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();

	/**
	 * 存放不同的 时区的Calendar Map
	 */
	private static Map<String, ThreadLocal<Calendar>> calendarThreadLocalMap = new HashMap<String, ThreadLocal<Calendar>>();


	/***
	 * 根据模版获取 SimpleDateFormat
	 * @param pattern
	 * @return
	 */
	private static SimpleDateFormat getSimpleDateFormat(final String pattern) {

		ThreadLocal<SimpleDateFormat> tl = simpleDateFormatThreadLocalHashMap.get(pattern);
		// 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
		if (tl == null) {
			synchronized (lockObj) {
				tl = simpleDateFormatThreadLocalHashMap.get(pattern);
				if (tl == null) {
					// 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map
					// 这里是关键,使用ThreadLocal<SimpleDateFormat>替代原来直接new SimpleDateFormat
					tl = new ThreadLocal<SimpleDateFormat>() {

						@Override
						protected SimpleDateFormat initialValue() {

							return new SimpleDateFormat(pattern);
						}
					};
					simpleDateFormatThreadLocalHashMap.put(pattern, tl);
				}
			}
		}
		return tl.get();
	}

	/***
	 * 根据模版获取  Calendar
	 * @param pattern
	 * @return
	 */
	private static Calendar getCalendar(final String pattern) {
		ThreadLocal<Calendar> tl = calendarThreadLocalMap.get(pattern);
		// 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
		if (tl == null) {
			synchronized (lockObj) {
				tl = calendarThreadLocalMap.get(pattern);
				if (tl == null) {
					// 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map
					System.out.println("put new sdf of pattern " + pattern + " to map");
					// 这里是关键,使用ThreadLocal<Calendar>替代原来直接new Calendar
					tl = new ThreadLocal<Calendar>() {
						@Override
						protected Calendar initialValue() {
							System.out.println("thread: " + Thread.currentThread() + " init pattern: " + pattern);
							// new GregorianCalendar(pattern);
							return Calendar.getInstance( TimeZone.getTimeZone(pattern)) ;
						}
					};
					calendarThreadLocalMap.put(pattern, tl);
				}
			}
		}
		return tl.get();


	}


	/**
	 * 获得某一月的天数集合
	 *
	 * @param year
	 * @param month
	 * @return
	 * @throws ParseException
	 */
	public static List<Date> getDateAry(int year, int month) throws ParseException {
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(getSimpleDateFormat(COMMON_DATE).parse("" + year + "-" + month + "-01"));
		int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		List<Date> dateList = new ArrayList<Date>();
		for (int i = 0; i < maxDays; i++) {
			dateList.add(calendar.getTime());
			calendar.add(Calendar.DAY_OF_MONTH, 1);
		}
		return dateList;
	}

	/**
	 * 日期转字符
	 *
	 * @param date
	 * @param pattern
	 * @return
	 */
	public static String dateToString(Date date, String pattern) {
		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
		return dateFormat.format(date);
	}

	/**
	 * 字符转日期
	 *
	 * @param date
	 * @param pattern
	 * @return
	 * @throws ParseException
	 */
	public static Date stringToDate(String date, String pattern) throws ParseException {
		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
		return dateFormat.parse(date);
	}


	/**
	 *  传入一个事件，计算加减法，单位年
	 * @param date  时间
	 * @param num  加减的数量
	 * @param type 增加，还是减少，请传入值：add    subtract
	 * @return
	 * @throws ParseException
	 */
	public static Date getYearAddAndSubtract(Date date, BigDecimal num , String type) throws Exception {

		if(type == null ){
			throw new RuntimeException("请传入运算类型");
		}
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(date);
		int nu =0;
		if("add".equalsIgnoreCase(type)){
			nu = num.intValue();
		}else{
			nu = num.negate().intValue();
		}
		calendar.add(Calendar.YEAR, nu);
		return calendar.getTime();
	}

	/**
	 * 传入年月 获取这个月的第一天
	 *
	 * @param year
	 * @param month
	 * @return
	 */
	public static String getStartTime(Integer year, Integer month) {
		Calendar calendar = getCalendar(UTC8);
		//设置年份
		calendar.set(Calendar.YEAR, year);
		//设置月份
		calendar.set(Calendar.MONTH, month - 1);
		//设置日历中月份的第1天
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		//格式化日期
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String firstDayOfMonth = sdf.format(calendar.getTime());
		return firstDayOfMonth;
	}

	/**
	 * 传入年月 获取这个月的最后 一天
	 *
	 * @param year
	 * @param month
	 * @return
	 */
	public static String getEndTime(Integer year, Integer month) {
		Calendar calendar = getCalendar(UTC8);
		//设置年份
		calendar.set(Calendar.YEAR, year);
		//设置月份
		calendar.set(Calendar.MONTH, month - 1);
		int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		calendar.set(Calendar.DAY_OF_MONTH, lastDay);
		//格式化日期
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String firstDayOfMonth = sdf.format(calendar.getTime());
		return firstDayOfMonth;
	}

	/**
	 * 传入时间所在月份得到第一天
	 *
	 * @param tempDate
	 * @return
	 */
	public static Date getStartTime(Date tempDate) {
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(tempDate);
		//设置日历中月份的第1天
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * 传入时间所在月份的最后 一天
	 *
	 * @param tempDate
	 * @return
	 */
	public static Date getEndTime(Date tempDate) {
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(tempDate);
		int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		calendar.set(Calendar.DAY_OF_MONTH, lastDay);
		return calendar.getTime();
	}

	/**
	 * 传入date 获取这个时间年的第一个月的第一天
	 *
	 * @param tempDate
	 * @return
	 */
	public static Date getStartMonth(Date tempDate) {
		Calendar cal = getCalendar(UTC8);
		cal.setTime(tempDate);
		//设置日历中月份的第1天
		cal.set(Calendar.DAY_OF_YEAR, 1);
		return cal.getTime();
	}

	/**
	 * 传入date 获取这个时间年的最后一个月的最后一天
	 *
	 * @param tempDate
	 * @return
	 */
	public static Date getEndMonth(Date tempDate) {
		Calendar cal = getCalendar(UTC8);
		cal.setTime(tempDate);
		int lastDay = cal.getActualMaximum(Calendar.DAY_OF_YEAR);
		cal.set(Calendar.DAY_OF_YEAR, lastDay);
		return cal.getTime();
	}

	public static Date getYearFirstDate(Date tempDate) {
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(tempDate);
		calendar.set(Calendar.DAY_OF_YEAR, 1);
		return calendar.getTime();
	}

	/**
	 * 时间类型的运算
	 *
	 * @param date 要运算的时间
	 * @param num  加一天 1  减一天 -1
	 * @return
	 */
	public static Date getDateoperation(Date date, Integer num) {
		/** 初始化日期格式工具*/
		Calendar calendar = getCalendar(UTC8);
		calendar.setTime(date);
		/** 设置预警时间*/
		calendar.add(Calendar.DATE, num);
		return calendar.getTime();
	}

	/**
	 * 取得日期：年
	 *
	 * @param date
	 * @return
	 */
	public static int getYear(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int year = c.get(Calendar.YEAR);
		return year;
	}

	/**
	 * 取得日期：年
	 *
	 * @param date
	 * @return
	 */
	public static int getMonth(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int month = c.get(Calendar.MONTH);
		return month + 1;
	}

	/**
	 * 取得日期：年
	 *
	 * @param date
	 * @return
	 */
	public static int getDay(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int da = c.get(Calendar.DAY_OF_MONTH);
		return da;
	}

	/**
	 * 取得当天日期是周几
	 *
	 * @param date
	 * @return
	 */
	public static int getWeekDay(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int week_of_year = c.get(Calendar.DAY_OF_WEEK);
		return week_of_year - 1;
	}

	/**
	 * 取得一年的第几周
	 *
	 * @param date
	 * @return
	 */
	public static int getWeekOfYear(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int week_of_year = c.get(Calendar.WEEK_OF_YEAR);
		return week_of_year;
	}


	/**
	 * 根据日期取得对应周周一日期
	 *
	 * @param date
	 * @return
	 */
	public static Date getMondayOfWeek(Date date) {
		Calendar monday = getCalendar(UTC8);
		monday.setTime(date);
		monday.setFirstDayOfWeek(FIRST_DAY_OF_WEEK);
		monday.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		return monday.getTime();
	}

	/**
	 * 根据日期取得对应周周日日期
	 *
	 * @param date
	 * @return
	 */
	public static Date getSundayOfWeek(Date date) {
		Calendar sunday = getCalendar(UTC8);
		sunday.setTime(date);
		sunday.setFirstDayOfWeek(FIRST_DAY_OF_WEEK);
		sunday.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
		return sunday.getTime();
	}

	/**
	 * 取得月的剩余天数
	 *
	 * @param date
	 * @return
	 */
	public static int getRemainDayOfMonth(Date date) {
		int dayOfMonth = getDayOfMonth(date);
		int day = getPassDayOfMonth(date);
		return dayOfMonth - day;
	}

	/**
	 * 取得月已经过的天数
	 *
	 * @param date
	 * @return
	 */
	public static int getPassDayOfMonth(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		return c.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 取得月天数
	 *
	 * @param date
	 * @return
	 */
	public static int getDayOfMonth(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		return c.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 取得月第一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getFirstDateOfMonth(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		c.set(Calendar.DAY_OF_MONTH, c.getActualMinimum(Calendar.DAY_OF_MONTH));
		return c.getTime();
	}

	/**
	 * 取得月最后一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getLastDateOfMonth(Date date) {
		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
		return c.getTime();
	}

	/**
	 * 取得季度第一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getFirstDateOfSeason(Date date) {
		return getFirstDateOfMonth(getSeasonDate(date)[0]);
	}

	/**
	 * 取得季度最后一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getLastDateOfSeason(Date date) {
		return getLastDateOfMonth(getSeasonDate(date)[2]);
	}

	/**
	 * 取得季度天数
	 *
	 * @param date
	 * @return
	 */
	public static int getDayOfSeason(Date date) {
		int day = 0;
		Date[] seasonDates = getSeasonDate(date);
		for (Date date2 : seasonDates) {
			day += getDayOfMonth(date2);
		}
		return day;
	}

	/**
	 * 取得季度剩余天数
	 *
	 * @param date
	 * @return
	 */
	public static int getRemainDayOfSeason(Date date) {
		return getDayOfSeason(date) - getPassDayOfSeason(date);
	}

	/**
	 * 取得季度已过天数
	 *
	 * @param date
	 * @return
	 */
	public static int getPassDayOfSeason(Date date) {
		int day = 0;

		Date[] seasonDates = getSeasonDate(date);

		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int month = c.get(Calendar.MONTH);

		if (month == Calendar.JANUARY || month == Calendar.APRIL
				|| month == Calendar.JULY || month == Calendar.OCTOBER) {// 季度第一个月
			day = getPassDayOfMonth(seasonDates[0]);
		} else if (month == Calendar.FEBRUARY || month == Calendar.MAY
				|| month == Calendar.AUGUST || month == Calendar.NOVEMBER) {// 季度第二个月
			day = getDayOfMonth(seasonDates[0])
					+ getPassDayOfMonth(seasonDates[1]);
		} else if (month == Calendar.MARCH || month == Calendar.JUNE
				|| month == Calendar.SEPTEMBER || month == Calendar.DECEMBER) {// 季度第三个月
			day = getDayOfMonth(seasonDates[0]) + getDayOfMonth(seasonDates[1])
					+ getPassDayOfMonth(seasonDates[2]);
		}
		return day;
	}

	/**
	 * 取得季度月
	 *
	 * @param date
	 * @return
	 */
	public static Date[] getSeasonDate(Date date) {
		Date[] season = new Date[3];

		Calendar c = getCalendar(UTC8);
		c.setTime(date);

		int nSeason = getSeason(date);
		if (nSeason == 1) {// 第一季度
			c.set(Calendar.MONTH, Calendar.JANUARY);
			season[0] = c.getTime();
			c.set(Calendar.MONTH, Calendar.FEBRUARY);
			season[1] = c.getTime();
			c.set(Calendar.MONTH, Calendar.MARCH);
			season[2] = c.getTime();
		} else if (nSeason == 2) {// 第二季度
			c.set(Calendar.MONTH, Calendar.APRIL);
			season[0] = c.getTime();
			c.set(Calendar.MONTH, Calendar.MAY);
			season[1] = c.getTime();
			c.set(Calendar.MONTH, Calendar.JUNE);
			season[2] = c.getTime();
		} else if (nSeason == 3) {// 第三季度
			c.set(Calendar.MONTH, Calendar.JULY);
			season[0] = c.getTime();
			c.set(Calendar.MONTH, Calendar.AUGUST);
			season[1] = c.getTime();
			c.set(Calendar.MONTH, Calendar.SEPTEMBER);
			season[2] = c.getTime();
		} else if (nSeason == 4) {// 第四季度
			c.set(Calendar.MONTH, Calendar.OCTOBER);
			season[0] = c.getTime();
			c.set(Calendar.MONTH, Calendar.NOVEMBER);
			season[1] = c.getTime();
			c.set(Calendar.MONTH, Calendar.DECEMBER);
			season[2] = c.getTime();
		}
		return season;
	}


	/**
	 * 1 第一季度 2 第二季度 3 第三季度 4 第四季度
	 *
	 * @param date
	 * @return
	 */
	public static int getSeason(Date date) {

		int season = 0;

		Calendar c = getCalendar(UTC8);
		c.setTime(date);
		int month = c.get(Calendar.MONTH);
		switch (month) {
			case Calendar.JANUARY:
			case Calendar.FEBRUARY:
			case Calendar.MARCH:
				season = 1;
				break;
			case Calendar.APRIL:
			case Calendar.MAY:
			case Calendar.JUNE:
				season = 2;
				break;
			case Calendar.JULY:
			case Calendar.AUGUST:
			case Calendar.SEPTEMBER:
				season = 3;
				break;
			case Calendar.OCTOBER:
			case Calendar.NOVEMBER:
			case Calendar.DECEMBER:
				season = 4;
				break;
			default:
				break;
		}
		return season;
	}


	public static void main(String[] args) {
		//   getCalendar(UTC8);
		TimeZone timeZone1 = TimeZone.getTimeZone("GMT+:08:00");
		System.out.println(timeZone1);
	}

	public static void main1(String[] args) {
		try {
			/** 初始化日期格式工具*/
			Calendar calendar = getCalendar(UTC8);
			/** 设置保质期时间*/
			calendar.setTime(stringToDate("2015-05-26", "yyyy-MM-dd"));
			/** 设置预警时间*/
			calendar.add(Calendar.DATE, 1);
			/** 得到预警日期*/
			System.out.println("保质期：2015-05-26");
			System.out.println("预警日期：" + dateToString(calendar.getTime(), "yyyy-MM-dd"));

			System.out.println(dateToString(getDateoperation(new Date(), 1), "yyyy-MM-dd"));
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
